#pragma once

#include "Misc/EngineEditorMacros.h"
#include "Widgets/EditorWidgetViewModel.h"
#include "Font/FontSubsystem.h"   
#include "Event/TextInputEvent.h"
#include "Event/KeyboardEvent.h"
#include "Framework/Tickable.h"
#include "EditorEditableTextViewModel.m.h"

RCLASS()
class REditorEditableTextViewModel : public REditorWidgetViewModel , public ITickable
{
    ROBJECT

public:
    REditorEditableTextViewModel();

    CString GetDisplayText() const { return DisplayText; }
    void SetDisplayText(CString InDisplayText) { 
        if(DisplayText == InDisplayText) 
        {
            return;
        }
        DisplayText = InDisplayText; 

        BeamPosition.CharacterIndex = 0;
        BeamPosition.X = 0;

        OnDisplayTextChanged.Broadcast();
    }
    
    TMultiCastDelegate<> OnDisplayTextChanged;

    void SetFont(TSharedObjectPtr<RFont> InFont) { Font = InFont; }
    TSharedObjectPtr<RFont> GetFont() const { return Font; }

    void SetFontSize(int64_t InFontSize) { FontSize = InFontSize; }
    int64_t GetFontSize() const { return FontSize; }


    const SColor BeamColor = SColor::White;
    float GetBeamX() const { return BeamPosition.X; }

    void StartEditing() { 
        bIsEditing = true; 
        CursorShowState=true;
        OnEditingStarted.Broadcast();
    }
    TMultiCastDelegate<> OnEditingStarted;

    enum class EReasonForEndEditing
    {
        Confirm,
        //Cancel,
        LostFocus
    };

    void EndEditing(EReasonForEndEditing InReasonForEndEditing) { 
        if(CanEndEditing.IsBound())
        {
            bool bCanEndEditing = CanEndEditing.Execute(InReasonForEndEditing);
            if(!bCanEndEditing)
            {
                return;
            }
        }

        bIsEditing = false; 
        CursorShowState=false;
        OnEditingEnded.Broadcast(InReasonForEndEditing);
    }
    //invoked before the editing is ended
    //return false if the editing can not be ended
    TDelegate<bool,EReasonForEndEditing> CanEndEditing;

    TMultiCastDelegate<EReasonForEndEditing> OnEditingEnded;

    bool IsEditing() const { return bIsEditing; }

    /// @brief 
    /// @param MouseRelativeX  The x position of the mouse relative to first character of the text 
    void OnMuseButtonClicked(float MouseRelativeX); 

    bool OnTextInput(const STextInputEvent& InTextInputEvent);
    bool OnKeyboardEvent(const SKeyboardEvent& InKeyboardEvent);

    void Tick(float DeltaSeconds) override;
protected:
    bool bIsEditing = false;
    CString DisplayText;

    TSharedObjectPtr<RFont> Font;
    int64_t FontSize = 12;

    RFontApplicationSubsystem::SCursorPosition BeamPosition;
    bool CursorShowState = true;
    float ElapsedTime = 0.0f;

public:
    bool bIsIMEWindowOpen=false;    

};